home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / macros / plain / contrib / tree.tex < prev    next >
Encoding:
Text File  |  1992-08-26  |  11.5 KB  |  309 lines

  1. %              Tree -- a macro to make aligned (horizontal) trees in TeX
  2. %
  3. %    Input is of the form
  4. %        \tree
  5. %           item
  6. %           \subtree
  7. %              \leaf{item}
  8. %                 .
  9. %                 .
  10. %                 .
  11. %           \endsubtree
  12. %           \subtree
  13. %              .
  14. %              .
  15. %              .
  16. %           \endsubtree
  17. %        \endsubtree
  18. %     \endtree
  19. %
  20. %    Nesting is to any level.  \leaf is defined as a subtree of one item:
  21. % \def\leaf#1{\subtree#1\endsubtree}.
  22. %
  23. %    A structure:
  24. %       \subtree
  25. %          item_part1
  26. %          item_part2
  27. %               .
  28. %               .
  29. %               .
  30. %
  31. % will print item_part2 directly below item_part1 as a single item
  32. % as if they were in a \box.
  33. %
  34. %    The macro is a 3-pass macro.  On the first pass it sets up a data
  35. % structure from the \subtree ... \endsubtree definitions.  On the second pass
  36. % it recursively calculates the width of each level of the tree.  On the third
  37. % pass it sets up the boxes, glue and rules.
  38. %
  39. %    By David Eppstein, TUGboat, vol. 6 (1985), no. 1, pp. 31--35.
  40. %    Transcribed by Margaret Kromer (peg), Feb., 1986.
  41. %
  42. %             Pass 1
  43. % At the end of pass 1, the tree is coded as a nested collection of \hboxes
  44. % and \vboxes.
  45. \newbox\treebox\newcount\treeboxcnt
  46. \def\tree{\message{Begin tree}\treeboxcnt=1\global\setbox\treebox=\boxtree}
  47. \def\subtree{\ettext \advance\treeboxcnt by 1 \boxtree}
  48. \def\leaf#1{\subtree#1\endsubtree}
  49. \def\endsubtree{\ettext \egroup \advance\treeboxcnt-1{}%
  50.              \ifnum\treeboxcnt=-1 \treeerrora\fi}
  51. \def\endtree{\endsubtree \ifnum\treeboxcnt>0 \treeerrorb\fi%
  52.              \settreesizes \typesettree \message{-- end tree}}
  53. % Error messages for unbalanced tree
  54. \def\treeerrora{\errhelp=\treeerrorahelp%
  55.              \errmessage{Unbalanced tree -- too many endsubtrees}}
  56. \newhelp\treeerrorahelp{There are more subtrees closed than opened}
  57. \def\treeerrorb{\errhelp=\treeerrorbhelp%
  58.              \errmessage{Unbalanced tree -- not enough endsubtrees}}
  59. \newhelp\treeerrorbhelp{Not all the subtrees of the tree are closed.
  60. If you continue, you'll get some mysterious secondary errors.}
  61. %        Set up \vbox containing root of tree
  62. \newif\iftreetext\treetextfalse         % Whether still aligning text
  63. \def\boxtree{\hbox\bgroup               % Start outer box of tree or subtree
  64.   \baselineskip 2.5ex                   % Narrow line spacing slightly
  65.   \tabskip 0pt                          % No spurious glue in alignment
  66.   \vbox\bgroup                          % Start inner text \vbox
  67.   \treetexttrue                         % Remember for \ettext
  68.   \let\par\crcr \obeylines              % New line breaks without explicit \cr
  69.   \halign\bgroup##\hfil\cr}             % Start alignment with simple template
  70. \def\ettext{\iftreetext                 % Are we still in inner text \vbox?
  71.   \crcr\egroup \egroup \fi}             % Yes, end alignment and box
  72. %             Pass 2
  73. % Recursively calculate widths of tree with \setsizes; keep results in
  74. % \treesizes; \treewidth contains total width calculated so far.  \treeworkbox
  75. % is workspace containing subtree being sized.
  76. \newbox\treeworkbox
  77. \def\cons#1#2{\edef#2{\xmark #1#2}}     % Add something to start of list
  78. \def\car#1{\expandafter\docar#1\docar}  % Take first element of list
  79. \def\docar\xmark#1\xmark#2\docar{#1}    % ..by ignoring rest in expansion
  80. \def\cdr#1{\expandafter\docdr#1\docdr#1}% Similarly, drop first element
  81. \def\docdr\xmark#1\xmark#2\docdr#3{\def#3{\xmark #2}}
  82. \def\xmark{\noexpand\xmark}             % List separator expands to self
  83. \def\nil{\xmark}                        % Empty list is just separator
  84. \def\settreesizes{\setbox\treeworkbox=\copy\treebox%
  85.               \global\let\treesizes\nil \setsizes}
  86. \newdimen\treewidth                     % Width of this part of the tree
  87. \def\setsizes{\setbox\treeworkbox=\hbox\bgroup% Get a horiz list as a workspace
  88.   \unhbox\treeworkbox\unskip            % Take tree, unpack it into horiz list
  89.   \inittreewidth                        % Get old width at this level
  90.   \sizesubtrees                         % Recurse through all subtrees
  91.   \sizelevel                            % Now set width from remaining \vbox
  92.   \egroup}                              % All done, finish our \hbox
  93. \def\inittreewidth{\ifx\treesizes\nil   % If this is the first at this level
  94.     \treewidth=0pt                      % ..then we have no previous max width
  95.  \else \treewidth=\car\treesizes        % Otherwise take old max level width
  96.    \global\cdr\treesizes                % ..and advance level width storage
  97.    \fi}                                 % ..in preparation for next level.
  98. \def\sizesubtrees{\loop                 % For each box in horiz list (subtree)
  99.   \setbox\treeworkbox=\lastbox \unskip  % ..pull it off list and flush glue
  100.   \ifhbox\treeworkbox \setsizes         % If hbox, it's a subtree - recurse
  101.   \repeat}                              % ..and loop; end loop on tree text
  102. \def\sizelevel{%
  103.   \ifdim\treewidth<\wd\treeworkbox      % If greater than previous maximum
  104.   \treewidth=\wd\treeworkbox \fi        % Then set max to new high
  105.  \global\cons{\the\treewidth}\treesizes}% In either case, put back on list
  106. %             Pass 3
  107. % Recursively typeset tree with \maketree by adding an \hbox containing
  108. % a subtree (in \treebox) to the horizontal list.
  109. \newdimen\treeheight                    % Height of this part of the tree
  110. \newif\ifleaf                           % Tree has no subtrees (is a leaf)
  111. \newif\ifbotsub                         % Bottom subtree of parent
  112. \newif\iftopsub                         % Top subtree of parent
  113. \def\typesettree{\medskip\maketree\medskip}  % Make whole tree
  114. \def\maketree{\hbox{\treewidth=\car\treesizes  % Get width at this level
  115.   \cdr\treesizes                        % Set up width list for recursion
  116.   \makesubtreebox\unskip                % Set \treebox to text, make subtrees
  117.   \ifleaf \makeleaf                     % No subtrees, add glue
  118.   \else \makeparent \fi}}               % Have subtrees, stick them at right
  119. {\catcode`@=11                          % Be able to use \voidb@x
  120. \gdef\makesubtreebox{\unhbox\treebox    % Open up tree or subtree
  121.   \unskip\global\setbox\treebox\lastbox % Pick up very last box
  122.   \ifvbox\treebox                       % If we're already at the \vbox
  123.     \global\leaftrue \let\next\relax    % ..then this is a leaf
  124.   \else \botsubtrue                     % Otherwise, we have subtrees
  125.     \setbox\treeworkbox\box\voidb@x     % Init stack of processed subs
  126.     \botsubtrue \let\next\makesubtree   % ..and call \maketree on them
  127.   \fi \next}}                           % Finish up for whichever it was
  128. \def\makesubtree{\setbox1\maketree      % Call \maketree on this subtree
  129.   \unskip\global\setbox\treebox\lastbox % Pick up box before it
  130.   \treeheight=\ht1                      % Get height of subtree we made
  131.   \advance\treeheight 2ex               % Add some room around the edges
  132.   \ifhbox\treebox \topsubfalse          % If picked up box is a \vbox,
  133.     \else \topsubtrue \fi               % ..this is the top, otherwise not
  134.   \addsubtreebox                        % Stack subtree with the rest
  135.   \iftopsub \global\leaffalse           % If top, remember not a leaf
  136.     \let\next\relax \else               % ..(after recursion), set return
  137.     \botsubfalse \let\next\makesubtree  % Otherwise, we have more subtrees
  138.   \fi \next}                            % Do tail recursion or return
  139. \def\addsubtreebox{\setbox\treeworkbox=\vbox{\subtreebox\unvbox\treeworkbox}}
  140. \def\subtreebox{\hbox\bgroup            % Start \hbox of tree and lines
  141.   \vbox to \treeheight\bgroup           % Start \vbox for vertical rules
  142.     \ifbotsub \iftopsub \vfil           % If both bottom and top subtree
  143.         \hrule width 0.4pt              % ..vertical rule is just a dot
  144.      \else \treehalfrule \fi \vfil      % Bottom gets half-height rule
  145.     \else \iftopsub \vfil \treehalfrule % Top gets half-height the other way
  146.      \else \hrule width 0.4pt height \treeheight \fi\fi % Middle, full height
  147.     \egroup                             % Finish vertical rule \vbox
  148.   \treectrbox{\hrule width 1em}\hskip 0.2em\treectrbox{\box1}\egroup}
  149. \def\treectrbox#1{\vbox to \treeheight{\vfil #1\vfil}}
  150. \def\treehalfrule{\dimen\treeworkbox=\treeheight   % Get total height
  151.   \divide\dimen\treeworkbox 2%
  152.   \advance\dimen\treeworkbox 0.2pt      % Divide by two, add half horiz height
  153.   \hrule width 0.4pt height \dimen\treeworkbox}% Make a vertical rule that high
  154. \def\makeleaf{\box\treebox}             % Add leaf box to horiz list
  155. \def\makeparent{\ifdim\ht\treebox>%
  156.     \ht\treeworkbox                     % If text is higher than subtrees
  157.     \treeheight=\ht\treebox             % ..use that height
  158.   \else \treeheight=\ht\treeworkbox \fi % Otherwise use height of subtrees
  159.   \advance\treewidth-\wd\treebox        % Take remainder of level width
  160.   \advance\treewidth 1em                % ..after accounting for text and glue
  161.   \treectrbox{\box\treebox}\hskip 0.2em % Add text, space before connection
  162. \treectrbox{\hrule width \treewidth}%
  163.   \treectrbox{\box\treeworkbox}}        % Add \hrule, subs
  164.  
  165. ************************************************
  166. % Plain TeX driver for tree.tex
  167.  
  168. \def\uncatcodespecials{\catcode`@=12\def\do##1{\catcode`##1=12}\dospecials}
  169. \def\setupverbatim{\tt\obeylines\uncatcodespecials\obeyspaces}
  170. {\obeyspaces\global\let =\ }
  171. \def\beginshowoff{\par\begingroup\setupverbatim\doverbatim}
  172. {\catcode`\!=0 \catcode`\\=12
  173. !obeylines!gdef!doverbatim^^M#1\endshowoff{#1!endgroup!medbreak!filbreak%
  174. !smallskip}}
  175.  
  176. % see The TeXbook, exercise 22.14
  177. \input tree.tex
  178. \centerline{\bf TREE TREE}
  179. \bigskip
  180. \tree
  181.   Tree
  182.   Uses
  183.   \subtree
  184.     Computer
  185.     Science
  186.     \subtree
  187.       Data
  188.       Structures
  189.       \leaf{Search Tree}
  190.       \leaf{Priority Queue}
  191.     \endsubtree
  192.     \subtree
  193.       Parsing
  194.       \leaf{Parse Tree}
  195.       \leaf{Symbol Table}
  196.     \endsubtree
  197.     \subtree
  198.       Structured
  199.       Programming
  200.     \endsubtree
  201.   \endsubtree
  202.   \subtree
  203.     Genealogy
  204.     \leaf{Ancestors}
  205.     \leaf{Descendants}
  206.   \endsubtree
  207.   \subtree
  208.     Electrical
  209.     Engineering
  210.     \subtree
  211.       Paper
  212.       \leaf{{\it Vitae}}
  213.       \leaf{Announcements}
  214.       \leaf{Proposals}
  215.       \leaf{\TeX{} Samples}
  216.     \endsubtree
  217.   \endsubtree
  218.   \subtree
  219.     Construction
  220.     \leaf{Fences}
  221.     \subtree
  222.       Buildings
  223.       \subtree
  224.         Houses
  225.         \leaf{Human}
  226.         \leaf{Dog}
  227.         \leaf{Bird}
  228.         \leaf{Tree}
  229.       \endsubtree
  230.       \leaf{Barns}
  231.       \leaf{Other}
  232.     \endsubtree
  233.     \leaf{\dots}
  234.   \endsubtree
  235.   \subtree
  236.     Taxonomies
  237.     \leaf{Tree Uses}
  238.   \endsubtree
  239. \endtree
  240.  
  241. \vskip.5truein
  242. \beginshowoff
  243. % see The TeXbook, exercise 22.14
  244. \input tree.tex
  245. \centerline{TREE TREE}
  246. \bigskip
  247. \tree
  248.   Tree
  249.   Uses
  250.   \subtree
  251.     Computer
  252.     Science
  253.     \subtree
  254.       Data
  255.       Structures
  256.       \leaf{Search Tree}
  257.       \leaf{Priority Queue}
  258.     \endsubtree
  259.     \subtree
  260.       Parsing
  261.       \leaf{Parse Tree}
  262.       \leaf{Symbol Table}
  263.     \endsubtree
  264.     \subtree
  265.       Structured
  266.       Programming
  267.     \endsubtree
  268.   \endsubtree
  269.   \subtree
  270.     Genealogy
  271.     \leaf{Ancestors}
  272.     \leaf{Descendants}
  273.   \endsubtree
  274.   \subtree
  275.     Electrical
  276.     Engineering
  277.     \subtree
  278.       Paper
  279.       \leaf{{\it Vitae}}
  280.       \leaf{Announcements}
  281.       \leaf{Proposals}
  282.       \leaf{\TeX{} Samples}
  283.     \endsubtree
  284.   \endsubtree
  285.   \subtree
  286.     Construction
  287.     \leaf{Fences}
  288.     \subtree
  289.       Buildings
  290.       \subtree
  291.         Houses
  292.         \leaf{Human}
  293.         \leaf{Dog}
  294.         \leaf{Bird}
  295.         \leaf{Tree}
  296.       \endsubtree
  297.       \leaf{Barns}
  298.       \leaf{Other}
  299.     \endsubtree
  300.     \leaf{\dots}
  301.   \endsubtree
  302.   \subtree
  303.     Taxonomies
  304.     \leaf{Tree Uses}
  305.   \endsubtree
  306. \endtree
  307. \endshowoff
  308. \bye
  309.